// src/main/services/file-service.ts
import { ipcMain } from 'electron';
import fs from 'fs';
import fsp from 'fs/promises';
import path from 'path';
import log from 'electron-log';
import https from 'https';
import http from 'http';
import { Readable } from 'stream';
import { pipeline } from 'stream/promises';
import Logger from 'electron-log';

// ==================== 类型定义 ====================
export interface FileOperationResult {
    success: boolean;
    data?: string | boolean | object;
    error?: string;
}

export interface FileReadOptions {
    encoding?: BufferEncoding;
}

export interface FileWriteOptions {
    encoding?: BufferEncoding;
    mode?: number;
    flag?: string;
}

export interface DirectoryOptions {
    recursive?: boolean;
    mode?: number;
}

export interface DownloadOptions {
    timeout?: number;
    headers?: Record<string, string>;
}

// ==================== 服务实现 ====================
export class FileService {
    /**
     * 读取文件内容
     */
    public async readFile(filePath: string, options: FileReadOptions = {}): Promise<FileOperationResult> {
        try {
            this.validatePath(filePath);
            const content = fs.readFileSync(filePath, { encoding: options.encoding || 'utf8' });
            return { success: true, data: content };
        } catch (error) {
            log.error('读取文件失败:', error);
            return { success: false, error: error instanceof Error ? error.message : '未知错误' };
        }
    }

    /**
     * 写入文件内容
     */
    public async writeFile(filePath: string, data: string, options: FileWriteOptions = {}): Promise<FileOperationResult> {
        try {
            this.validatePath(filePath);
            fs.writeFileSync(filePath, data, options);
            return { success: true };
        } catch (error) {
            log.error('写入文件失败:', error);
            return { success: false, error: error instanceof Error ? error.message : '未知错误' };
        }
    }

    /**
     * 追加内容到文件
     */
    public async appendFile(filePath: string, data: string, options: FileWriteOptions = {}): Promise<FileOperationResult> {
        try {
            this.validatePath(filePath);
            fs.appendFileSync(filePath, data, options);
            return { success: true };
        } catch (error) {
            log.error('追加文件内容失败:', error);
            return { success: false, error: error instanceof Error ? error.message : '未知错误' };
        }
    }

    /**
     * 检查文件或目录是否存在
     */
    public async exists(filePath: string): Promise<FileOperationResult> {
        try {
            this.validatePath(filePath);
            const exists = fs.existsSync(filePath);
            return { success: true, data: exists };
        } catch (error) {
            log.error('检查文件存在性失败:', error);
            return { success: false, error: error instanceof Error ? error.message : '未知错误' };
        }
    }

    /**
     * 创建目录
     */
    public async mkdir(dirPath: string, options: DirectoryOptions = {}): Promise<FileOperationResult> {
        try {
            this.validatePath(dirPath);
            fs.mkdirSync(dirPath, { recursive: options.recursive ?? true, mode: options.mode });
            return { success: true };
        } catch (error) {
            log.error('创建目录失败:', error);
            return { success: false, error: error instanceof Error ? error.message : '未知错误' };
        }
    }

    /**
     * 读取目录内容
     */
    public async readdir(dirPath: string): Promise<FileOperationResult> {
        try {
            this.validatePath(dirPath);
            const files = fs.readdirSync(dirPath);
            return { success: true, data: files };
        } catch (error) {
            log.error('读取目录失败:', error);
            return { success: false, error: error instanceof Error ? error.message : '未知错误' };
        }
    }

    /**
     * 删除文件
     */
    public async unlink(filePath: string): Promise<FileOperationResult> {
        try {
            this.validatePath(filePath);
            fs.unlinkSync(filePath);
            return { success: true };
        } catch (error) {
            log.error('删除文件失败:', error);
            return { success: false, error: error instanceof Error ? error.message : '未知错误' };
        }
    }

    /**
     * 删除目录
     */
    public async rmdir(dirPath: string, recursive: boolean = true): Promise<FileOperationResult> {
        try {
            this.validatePath(dirPath);
            fs.rmSync(dirPath, { recursive });
            return { success: true };
        } catch (error) {
            log.error('删除目录失败:', error);
            return { success: false, error: error instanceof Error ? error.message : '未知错误' };
        }
    }

    /**
     * 获取文件信息
     */
    public async stat(filePath: string): Promise<FileOperationResult> {
        try {
            this.validatePath(filePath);
            const stats = fs.statSync(filePath);
            return {
                success: true,
                data: {
                    size: stats.size,
                    isFile: stats.isFile(),
                    isDirectory: stats.isDirectory(),
                    createdAt: stats.birthtime,
                    modifiedAt: stats.mtime
                }
            };
        } catch (error) {
            log.error('获取文件信息失败:', error);
            return { success: false, error: error instanceof Error ? error.message : '未知错误' };
        }
    }

    /**
     * 复制文件
     */
    public async copyFile(sourcePath: string, destPath: string): Promise<FileOperationResult> {
        try {
            this.validatePath(sourcePath);
            this.validatePath(destPath);
            fs.copyFileSync(sourcePath, destPath);
            return { success: true };
        } catch (error) {
            log.error('复制文件失败:', error);
            return { success: false, error: error instanceof Error ? error.message : '未知错误' };
        }
    }

    /**
     * 下载文件
     */
    public async downloadFile(url: string, destPath: string, options: DownloadOptions = {}): Promise<FileOperationResult> {
        try {
            Logger.info(`开始下载文件: ${url} ${destPath}`);
            this.validatePath(destPath);

            // 确保目标文件的目录存在
            const dirPath = path.dirname(destPath);
            await fsp.mkdir(dirPath, { recursive: true, mode: 0o755});


            const fileStream = fs.createWriteStream(destPath);

            const downloadPromise = new Promise<void>((resolve, reject) => {
                const request = (url.startsWith('https') ? https : http).get(url, {
                    timeout: options.timeout || 30000,
                    headers: options.headers || {}
                }, (response) => {
                    if (response.statusCode !== 200) {
                        reject(new Error(`下载失败，HTTP状态码: ${response.statusCode}`));
                        return;
                    }

                    response.pipe(fileStream);

                    fileStream.on('finish', () => {
                        fileStream.close();
                        resolve();
                    });

                    fileStream.on('error', (err) => {
                        reject(err);
                    });
                });

                request.on('error', (err) => {
                    reject(err);
                });

                request.on('timeout', () => {
                    request.destroy();
                    reject(new Error('下载超时'));
                });
            });

            await downloadPromise;
            return { success: true };
        } catch (error) {
            log.error('下载文件失败:', error);
            return { success: false, error: error instanceof Error ? error.message : '未知错误' };
        }
    }

    /**
     * 解压 ZIP 文件
     */
    public async unzipFile(zipPath: string, destPath: string): Promise<FileOperationResult> {
        try {
            this.validatePath(zipPath);
            this.validatePath(destPath);

            // 动态导入 yauzl-promise，避免在没有安装时导致整个模块加载失败
            const { default: yauzl } = await import('yauzl-promise');

            // 确保目标目录存在
            await fsp.mkdir(destPath, { recursive: true });

            const zip = await yauzl.open(zipPath);

            try {
                for await (const entry of zip) {
                    const entryPath = path.join(destPath, entry.filename);

                    // 防止路径遍历漏洞
                    if (!entryPath.startsWith(path.resolve(destPath))) {
                        log.warn(`试图解压到目录外的文件: ${entry.filename}`);
                        continue;
                    }

                    if (entry.filename.endsWith('/')) {
                        // 创建目录
                        await fsp.mkdir(entryPath, { recursive: true });
                    } else {
                        // 创建父目录
                        const parentDir = path.dirname(entryPath);
                        await fsp.mkdir(parentDir, { recursive: true });

                        // 解压文件
                        const readStream = await entry.openReadStream();
                        const writeStream = fs.createWriteStream(entryPath);

                        await pipeline(readStream, writeStream);
                    }
                }
            } finally {
                await zip.close();
            }

            return { success: true };
        } catch (error) {
            log.error('解压文件失败:', error);
            return { success: false, error: error instanceof Error ? error.message : '未知错误' };
        }
    }

    // ================ 私有方法 ================
    private validatePath(filePath: string) {
        // 确保路径是字符串
        if (typeof filePath !== 'string') {
            throw new Error('路径必须是字符串');
        }

        // 基本路径安全性检查
        if (filePath.includes('\0')) {
            throw new Error('路径不能包含空字符');
        }

        // 规范化路径以防止目录遍历攻击
        const normalizedPath = path.normalize(filePath);

        // 可以添加更多路径验证逻辑，例如限制访问特定目录
    }
}

// ==================== IPC 安全暴露 ====================
export function registerFileIPC(service: FileService) {
    ipcMain.handle('file:read', (_, filePath: string, options?: FileReadOptions) =>
        service.readFile(filePath, options)
    );

    ipcMain.handle('file:write', (_, filePath: string, data: string, options?: FileWriteOptions) =>
        service.writeFile(filePath, data, options)
    );

    ipcMain.handle('file:append', (_, filePath: string, data: string, options?: FileWriteOptions) =>
        service.appendFile(filePath, data, options)
    );

    ipcMain.handle('file:exists', (_, filePath: string) =>
        service.exists(filePath)
    );

    ipcMain.handle('file:mkdir', (_, dirPath: string, options?: DirectoryOptions) =>
        service.mkdir(dirPath, options)
    );

    ipcMain.handle('file:readdir', (_, dirPath: string) =>
        service.readdir(dirPath)
    );

    ipcMain.handle('file:unlink', (_, filePath: string) =>
        service.unlink(filePath)
    );

    ipcMain.handle('file:rmdir', (_, dirPath: string, recursive?: boolean) =>
        service.rmdir(dirPath, recursive)
    );

    ipcMain.handle('file:stat', (_, filePath: string) =>
        service.stat(filePath)
    );

    ipcMain.handle('file:copy', (_, sourcePath: string, destPath: string) =>
        service.copyFile(sourcePath, destPath)
    );

    ipcMain.handle('file:download', (_, url: string, destPath: string, options?: DownloadOptions) =>
        service.downloadFile(url, destPath, options)
    );

    ipcMain.handle('file:unzip', (_, zipPath: string, destPath: string) =>
        service.unzipFile(zipPath, destPath)
    );
}

// ==================== 单例导出 ====================
export const fileService = new FileService();